package com.vtech.ont.tdb.jdbc;

import org.apache.jena.jdbc.tdb.TDBDriver;
import org.egc.commons.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;

/**
 * TODO TEST & Refactor
 * <pre>
 * https://github.com/apache/jena/tree/trunk/jena-jdbc
 *
 * Driver Class: org.apache.jena.jdbc.tdb.TDBDriver
 * Driver URL Prefix: jdbc:jena:tdb:
 * Driver Parameters:
 *
 * location=/path/to/dataset
 *
 * Sets the location of the TDB dataset to create/load, may use the special location memory to specify a non-persistent in-memory TDB dataset.
 *
 * must-exist=true
 *
 * If set then ensures that only existing TDB datasets may be used, prevents incorrect paths leading to unexpected empty datasets
 * @author houzhiwei
 * @date 2017/7/13 22:14
 * @since 1.0
 */
public class TdbConnector implements JdbcConnector {

    private static final Logger log = LoggerFactory.getLogger(TdbConnector.class);

    private Connection conn;

    public TdbConnector(String tdbLoc, boolean mustExist) {
        try {
            conn = createTdbConnection(tdbLoc, mustExist);
            log.info("Jena TDB [ " + tdbLoc + " ] connected.");
        } catch (SQLException e) {
            log.error("Create Jena TDB JDBC Connection failed! " + e.getLocalizedMessage());
            throw new BusinessException(e, "Create Jena TDB JDBC Connection failed! " + e.getLocalizedMessage());
        }
    }

    @Override
    public ResultSet query(String sparql) {
        Statement stmt = createStmt();
        try {
            ResultSet rset = stmt.executeQuery(sparql);
//            stmt.close();  // Clean up
            return rset;
        } catch (SQLException e) {
            log.error("Execute SPARQL query failed! " + e.getLocalizedMessage());
            throw new BusinessException(e, "Execute SPARQL query failed! " + e.getLocalizedMessage());
        }
//        finally {
//            closeStmt(stmt);
//        }
    }

    @Override
    public int update(String sparql) {
        Statement stmt = createStmt();
        try {
            int i = stmt.executeUpdate(sparql);
            stmt.close();  // Clean up
            return i;
        } catch (SQLException e) {
            log.error("Execute SPARQL update failed! " + e.getLocalizedMessage());
            throw new BusinessException(e, "Execute SPARQL update failed! " + e.getLocalizedMessage());
        } finally {
            closeStmt(stmt);
        }
    }

    private Statement createStmt() {
        try {
            return conn.createStatement();
        } catch (SQLException e) {
            throw new BusinessException(e, "Create TDB JDBC statement failed!");
        }
    }

    private void closeStmt(Statement stmt) {
        try {
            stmt.close();
        } catch (SQLException e) {
            throw new BusinessException(e, "Close TDB JDBC statement failed!");
        }
    }

    /**
     * Create tdb jdbc connection.
     *
     * @param tdbLoc    the path to a location for a TDB dataset
     * @param mustExist is tdb must exist
     * @return the connection
     * @throws SQLException the sql exception
     */
    protected Connection createTdbConnection(String tdbLoc, boolean mustExist) throws SQLException {
        TDBDriver.register();
        String connection = "jdbc:jena:tdb:location=" + tdbLoc;
        if (mustExist)
            connection += connection + "&must-exist=true";
        Connection conn = DriverManager.getConnection(connection);
        return conn;
    }
}
